
#ifndef __GSL_EXT_MULTIMIN_H__

#ifdef __cplusplus
extern "C" {
#endif

#include <gsl/gsl_multimin.h>

typedef struct
{
  double (*f) (const gsl_vector *x, void *params);
  void (*df) (const gsl_vector * x, void *params, gsl_vector * df);
  void (*fdf) (const gsl_vector *x, void *params,
               double *f, gsl_vector *df);
  size_t n;
  void *params;
  void (*d2f) (const gsl_vector *x, void *params, gsl_matrix *d2f);
  void (*fd2f) (const gsl_vector *x, void *params,double *f, 
                gsl_vector *df, gsl_matrix *d2f);
}
gsl_ext_multimin_function_fd2f;

typedef struct
{
  const char *name;
  size_t size;
  int (*alloc) (void *state, size_t n);
  int (*set) (void *state, gsl_ext_multimin_function_fd2f *fd2f,
              const gsl_vector *x, double *f,
              gsl_vector *gradient, gsl_matrix *hessian,
              double step_size, double tol);
  int (*iterate) (void *state,gsl_ext_multimin_function_fd2f *fd2f,
                  gsl_vector *x, double *f,
                  gsl_vector *gradient, gsl_matrix *hessian,
                  gsl_vector *dx);
  int (*restart) (void *state);
  void (*free) (void *state);
}
gsl_ext_multimin_fd2fminimizer_type;

typedef struct
{
  const gsl_ext_multimin_fd2fminimizer_type *type;
  gsl_ext_multimin_function_fd2f *fd2f;

  double f;
  gsl_vector *x;
  gsl_vector *gradient;
  gsl_matrix *hessian;
  gsl_vector *dx;

  void *state;
}
gsl_ext_multimin_fd2fminimizer;

#define GSL_EXT_MULTIMIN_FN_EVAL_D2F(F,x,H) (*((F)->d2f))(x,(F)->params,(H))
#define GSL_EXT_MULTIMIN_FN_EVAL_F_D2F(F,x,f,g,H) (*((F)->fd2f))(x,(F)->params,(f),(g),(H))

gsl_ext_multimin_fd2fminimizer *
gsl_ext_multimin_fd2fminimizer_alloc (const gsl_ext_multimin_fd2fminimizer_type * T,
                                    size_t n);

int
gsl_ext_multimin_fd2fminimizer_set (gsl_ext_multimin_fd2fminimizer *s,
                                  gsl_ext_multimin_function_fd2f *fd2f,
                                  const gsl_vector *x,
                                  double step_size, double tol);

void
gsl_ext_multimin_fd2fminimizer_free(gsl_ext_multimin_fd2fminimizer *s);

int
gsl_ext_multimin_fd2fminimizer_iterate(gsl_ext_multimin_fd2fminimizer *s);

int
gsl_ext_multimin_fd2fminimizer_restart(gsl_ext_multimin_fd2fminimizer *s);

const char * 
gsl_ext_multimin_fd2fminimizer_name(const gsl_ext_multimin_fd2fminimizer *s);

gsl_vector * 
gsl_ext_multimin_fd2fminimizer_x(const gsl_ext_multimin_fd2fminimizer *s);

gsl_vector * 
gsl_ext_multimin_fd2fminimizer_dx(const gsl_ext_multimin_fd2fminimizer *s);

gsl_vector * 
gsl_ext_multimin_fd2fminimizer_gradient(const gsl_ext_multimin_fd2fminimizer *s);

gsl_matrix * 
gsl_ext_multimin_fd2fminimizer_hessian(const gsl_ext_multimin_fd2fminimizer *s);

double 
gsl_ext_multimin_fd2fminimizer_minimum(const gsl_ext_multimin_fd2fminimizer *s);

extern const gsl_multimin_fminimizer_type        *gsl_ext_multimin_fminimizer_lrwwsimplex;
extern const gsl_multimin_fdfminimizer_type      *gsl_ext_multimin_fdfminimizer_bfgs_hess_f;
extern const gsl_multimin_fdfminimizer_type      *gsl_ext_multimin_fdfminimizer_bfgs_f;
extern const gsl_multimin_fdfminimizer_type      *gsl_ext_multimin_fdfminimizer_bfgs_hess_mt;
extern const gsl_multimin_fdfminimizer_type      *gsl_ext_multimin_fdfminimizer_bfgs_mt;
extern const gsl_multimin_fdfminimizer_type      *gsl_ext_multimin_fdfminimizer_conjgrad_fr_mt;
extern const gsl_multimin_fdfminimizer_type      *gsl_ext_multimin_fdfminimizer_conjgrad_pr_mt;
extern const gsl_ext_multimin_fd2fminimizer_type *gsl_ext_multimin_fd2fminimizer_mnewton;

#ifdef __cplusplus
}
#endif

#define __GSL_EXT_MULTIMIN_H__

#endif
